#pragma once
#include "DXContext.h"
#include "ErrorCodes.h"
#include "NativePointer.h"
#include "enums.h"
#include "D3DResource.h"


namespace DXBase
{
	namespace D3D
	{
	    [Windows::Foundation::Metadata::WebHostHidden]
		public ref class SubresourceData sealed
		{
		public:
			SubresourceData() {}
			SubresourceData(IPointer^ p)
			{
				Mem = p;
			}

			property IPointer^ Mem;
			property uint32 MemRowPitch;
			property uint32 MemSlicePitch;
		};

		[Windows::Foundation::Metadata::WebHostHidden]
		public ref class Buffer sealed : IResource
		{
		private:
			DXBase::ContextWatcher watcher;
			D3D11_BUFFER_DESC desc;
			SubresourceData^ initData;
			NativeResource^ nresource;
			NativeShaderResourceView^ shaderResView;

		internal:
			Microsoft::WRL::ComPtr<ID3D11Buffer> buffer;

			virtual property DXContext^ Context 
			{
				DXContext^ get() = IContextBound::Context::get { return watcher.Context; } 
				void set(DXContext^ ctxt) = IContextBound::Context::set { watcher.Context = ctxt; }
			}
			virtual void ClearDXData() = IContextBound::ClearDXData 
			{
				buffer = nullptr; 
				nresource = nullptr;
				shaderResView = nullptr;
			}
			virtual void LoadDXData() = IContextBound::LoadDXData;

			Microsoft::WRL::ComPtr<ID3D11Buffer> GetUpdatedBuffer();

			virtual NativeShaderResourceView^ GetNativeShaderResourceView() = IResource::GetNativeShaderResourceView;
			virtual NativeResource^ GetNativeResource() = IResource::GetNativeResource;

		public:
			Buffer()
			{
				watcher.Target = this;
				desc.CPUAccessFlags = D3D11_USAGE_DEFAULT;
			}

			// call this when the content of the InitData pointer has changed
			void UpdateBuffer();

			// IResource
			virtual MappedSubresource^ Map(uint32 subresource, D3D::Map mapType, MapFlag flag) { return Resource_Map(this, subresource, mapType, flag); }
			virtual void CopyTo(IResource^ other) { Resource_CopyTo(this, other); }

			property SubresourceData^ InitData
			{
				SubresourceData^ get() { return initData; }
				void set(SubresourceData^ value) 
				{
					if (value == initData)
						return;
					initData = value;
					UpdateBuffer();
				}
			}

			property USAGE Usage
			{
				USAGE get() { return fromD3D(desc.Usage); }
				void set(USAGE value) 
				{
					auto v = makeD3D(value);
					if (v == desc.Usage)
						return;
					desc.Usage = v;
					ClearDXData();
				}
			}
			property BindFlag BindFlags
			{
				BindFlag get() { return (BindFlag)desc.BindFlags; }
				void set(BindFlag value) 
				{
					auto v = makeD3D(value);
					if (v == desc.BindFlags)
						return;
					desc.BindFlags = v;
					ClearDXData();
				}
			}
			property CPUAccessFlag CPUAccessFlags
			{
				CPUAccessFlag get() { return (CPUAccessFlag)desc.CPUAccessFlags; }
				void set(CPUAccessFlag value) 
				{
					auto v = makeD3D(value);
					if (v == desc.CPUAccessFlags)
						return;
					desc.CPUAccessFlags = v;
					ClearDXData();
				}
			}
			property ResourceMiscFlag MiscFlags
			{
				ResourceMiscFlag get() { return (ResourceMiscFlag)desc.MiscFlags; }
				void set(ResourceMiscFlag value) 
				{
					auto v = makeD3D(value);
					if (v == desc.MiscFlags)
						return;
					desc.MiscFlags = v;
					ClearDXData();
				}
			}
			property uint32 StructureByteStride
			{
				uint32 get() { return desc.StructureByteStride; }
				void set(uint32 value) 
				{
					if (value == desc.StructureByteStride)
						return;
					desc.StructureByteStride = value;
					ClearDXData();
				}
			}
		};

	}
}